package schedule

import (
	"gddgame.cc/galaxy/asteroid"
	"gddgame.cc/galaxy/asteroid/cluster"
	"gddgame.cc/galaxy/binocle"
	"gddgame.cc/galaxy/binocle/plugins/notice"
	. "gddgame.cc/galaxy/common/dsl/db"
	. "gddgame.cc/galaxy/common/dsl/web"
	"gddgame.cc/galaxy/server/composer"
	"gddgame.cc/galaxy/server/web"
)

const PluginName = "schedule"

var (
	currentClient *cluster.Client
)

func init() {
	RegisterPlugin(PluginProvider{
		Name:    PluginName,
		Depends: []string{notice.PluginName},

		OnInit: func(builder composer.Builder, core binocle.CoreClient) error {
			core.OnFinish(func() {
				core.OnObserver(func(observer string) {
					reloadSchedule(builder, core)
				})
				reloadSchedule(builder, core)
			})
			core.MountClient(func(client *cluster.Client) {
				currentClient = client
				// 绑定存储接口
				client.On("reload/schedule", func(message asteroid.Message) {
					reloadSchedule(builder, core)
				})
			})

			AddTable(&Table{
				Model: ServerScheduleModel,
			})
			return nil
		},
		BindRouter: BindRouter,
	})
}

func BindRouter(builder composer.Builder, core binocle.CoreClient, r *SwaggerRouter) {
	router := r.Router
	router.Put("/server/{server}/reload/schedule", func(context web.Context, next web.Next) error {
		currentClient.All().Send("reload/schedule")
		return next(nil)
	})
	r.Put("/server/{server}/verify/schedule", Swagger{
		Controller: func(context web.Context, server string, command string) (interface{}, error) {
			result := make(chan map[string]interface{})
			core.VerifySchedule(server, command, result)
			return <-result, nil
		},
		Params: []Param{
			{Name: "server", In: Path, Required: true},
			{Name: "command", In: Body, Required: true},
		},
		Response: ApiResponse,
	})
}

func reloadSchedule(builder composer.Builder, core binocle.CoreClient) {
	builder.Infof("[ Schedule ] Reload Schedule Start")
	client := core.Client()
	// 加载所有计划任务
	servers := core.Observers("")
	proxy := core.NewScheduleProxy()
	proxy.OnSuccess(func(observer string, name string, cron string, command string) {
		_ = notice.SendNotice(builder, "schedule.success", map[string]interface{}{
			"server":  observer,
			"name":    name,
			"cron":    cron,
			"command": command,
			"message": "Success",
		})
	})
	proxy.OnError(func(observer string, name string, cron string, command string, err error) {
		_ = ErrorSchedule(builder, observer, cron, command, err)
		_ = notice.SendNotice(builder, "schedule.error", map[string]interface{}{
			"server":  observer,
			"name":    name,
			"cron":    cron,
			"command": command,
			"message": err.Error(),
		})
	})
	for key := range servers {
		if client.CurrentNode() == core.AllocObserver(key) {
			schedules, err := GetScheduleAll(builder, key)
			if err != nil {
				continue
			}
			for _, schedule := range schedules {
				if err := proxy.SetSchedule(key, schedule.Name, schedule.Cron, schedule.Command, schedule.Type); err != nil {
					builder.Errorf("[ Schedule ]", err)
				}
			}
		} else {
			builder.Debugf("[ Schedule ] Server %s alloc %s, local: %s", key, core.AllocObserver(key), client.CurrentNode())
		}
	}
	core.SwitchScheduleProxy(proxy)
	builder.Infof("[ Schedule ] Reload Schedule End")
}
